package view;

import domein.Client;
import domein.MessageObservable;
import domein.OnlineUsersObservable;
import domein.ReceivingFileObservable;
import domein.SendingFileObservable;
import domein.StateObservable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Observable;
import java.util.Observer;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
 *
 * @author Colin Bundervoet
 * @author Jeroen Pattyn
 */
public class ClientFrame extends JFrame implements ActionListener, Observer
{
    private ServerFrame serverFrame;
    private Client client = null;
    private JLabel lblServer, lblUser, lblPort;
    private JTextField txtServer, txtUser, txtPort;
    private JButton btnConnect, btnDisconnect, btnLocalServer, btnSend;
    private JTextArea txtAreaMessages, txtAreaChat;
    private JList lstOnlineUsers;
    private JScrollPane scrlPaneMessages, scrlPaneChat, scrlPaneOnlineUsers;

    ;

    /**
     * Default Constructor for ClientFrame
     */
    public ClientFrame() {
        super("ChIrc");

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500, 300);
        setLocationRelativeTo(null);

        initComponents();
        setLayout();

        client = new Client();
        client.addMessageObserver(this);
        client.addOnlineUsersObserver(this);
        client.addStateObserver(this);
        client.addReceivingFileObserver(this);
        client.addSendingFileObserver(this);

        this.addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent e) {
                client.disconnect();
            }
        });

        setInitialState();
        setVisible(true);
    }

    private void initComponents() {
        lblServer = new JLabel("Server");
        lblUser = new JLabel("Username");
        lblPort = new JLabel("Port");
        txtServer = new JTextField(50);
        txtUser = new JTextField(50);
        txtPort = new JTextField();
        btnConnect = new JButton("Connect");
        btnConnect.addActionListener(this);
        btnDisconnect = new JButton("Disconnect");
        btnDisconnect.addActionListener(this);
        btnLocalServer = new JButton("Local Server");
        btnLocalServer.addActionListener(this);
        btnSend = new JButton("Send");
        btnSend.addActionListener(this);
        txtAreaMessages = new JTextArea();
        txtAreaMessages.setEditable(false);
        txtAreaChat = new JTextArea();
        txtAreaChat.addKeyListener(new KeyAdapter()
        {
            @Override
            public void keyReleased(KeyEvent e) {
                if (KeyEvent.VK_ENTER == e.getKeyCode()) {
                    if (!e.isShiftDown()) {
                        client.sendMessage(txtAreaChat.getText());
                        txtAreaChat.setText("");
                    }
                    else {
                        txtAreaChat.append("\n");
                    }
                }
            }
        });
        lstOnlineUsers = new JList();
        lstOnlineUsers.addMouseListener(new MouseAdapter()
        {
            @Override
            public void mouseClicked(MouseEvent e) {
                JPopupMenu popupMenu = new JPopupMenu();
                JMenuItem kickButton, whoIsButton, opButton, deOpButton, banButton, sendFileButton;
                popupMenu.add(kickButton = new JMenuItem("Kick"));
                popupMenu.add(whoIsButton = new JMenuItem("Whois"));
                popupMenu.add(opButton = new JMenuItem("Set op"));
                popupMenu.add(deOpButton = new JMenuItem("De-op"));
                popupMenu.add(banButton = new JMenuItem("Ban"));
                popupMenu.add(sendFileButton = new JMenuItem("Send file"));
                kickButton.addActionListener(new ActionListener()
                {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        client.sendMessage("/kick " + lstOnlineUsers.getSelectedValue().toString());
                    }
                });
                whoIsButton.addActionListener(new ActionListener()
                {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        client.sendMessage("/whois " + lstOnlineUsers.getSelectedValue().toString());
                    }
                });
                banButton.addActionListener(new ActionListener()
                {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        client.sendMessage("/ban " + lstOnlineUsers.getSelectedValue().toString());
                    }
                });
                opButton.addActionListener(new ActionListener()
                {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        client.sendMessage("/op " + lstOnlineUsers.getSelectedValue().toString());
                    }
                });
                deOpButton.addActionListener(new ActionListener()
                {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        client.sendMessage("/deop " + lstOnlineUsers.getSelectedValue().toString());
                    }
                });
                sendFileButton.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent e) {
                        client.sendMessage("/filetransfer " + lstOnlineUsers.getSelectedValue().toString());
                    }
                });

                if (SwingUtilities.isRightMouseButton(e)
                    && !lstOnlineUsers.isSelectionEmpty() && lstOnlineUsers.locationToIndex(e.getPoint()) == lstOnlineUsers.getSelectedIndex()) {
                    popupMenu.show(lstOnlineUsers, e.getX(), e.getY());
                }
            }
        });
        scrlPaneMessages = new JScrollPane();

        scrlPaneMessages.setViewportView(txtAreaMessages);
        scrlPaneChat = new JScrollPane();

        scrlPaneChat.setViewportView(txtAreaChat);
        scrlPaneOnlineUsers = new JScrollPane();

        scrlPaneOnlineUsers.setViewportView(lstOnlineUsers);
    }

    private void setLayout() {
        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                .addComponent(lblServer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(lblUser, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                .addGap(18, 18, 18)
                .addComponent(txtUser, javax.swing.GroupLayout.PREFERRED_SIZE, 158, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(18, 18, 18)
                .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, 158, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addGap(27, 27, 27)
                .addComponent(lblPort, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                .addGroup(layout.createSequentialGroup()
                .addComponent(btnConnect, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(btnDisconnect, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addComponent(btnLocalServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                .addComponent(scrlPaneChat, javax.swing.GroupLayout.DEFAULT_SIZE, 505, Short.MAX_VALUE)
                .addComponent(scrlPaneMessages))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                .addComponent(scrlPaneOnlineUsers, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
                .addComponent(btnSend, javax.swing.GroupLayout.DEFAULT_SIZE, 205, Short.MAX_VALUE))))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)));
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(lblServer, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(lblPort, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(btnConnect)
                .addComponent(btnDisconnect))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(lblUser, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(txtUser, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addComponent(btnLocalServer))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(scrlPaneMessages, javax.swing.GroupLayout.DEFAULT_SIZE, 222, Short.MAX_VALUE)
                .addComponent(scrlPaneOnlineUsers, javax.swing.GroupLayout.DEFAULT_SIZE, 222, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                .addComponent(btnSend, javax.swing.GroupLayout.DEFAULT_SIZE, 84, Short.MAX_VALUE)
                .addComponent(scrlPaneChat, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
                .addContainerGap()));

        pack();
    }

    private void setInitialState() {
        txtServer.setText("localhost");
        txtPort.setText("5000");
        btnDisconnect.setEnabled(false);
        btnSend.setEnabled(false);
        txtAreaChat.setEnabled(false);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == btnSend) {
            client.sendMessage(txtAreaChat.getText());
            txtAreaChat.setText("");
        }
        else if (e.getSource() == btnConnect) {
            client.connect(txtServer.getText(), txtPort.getText(), txtUser.getText());
        }
        else if (e.getSource() == btnDisconnect) {
            client.disconnect();
            txtAreaChat.setText("");
        }
        else if (e.getSource() == btnLocalServer) {
            if (this.serverFrame == null) {
                serverFrame = new ServerFrame();
            }
            serverFrame.setVisible(true);
        }
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o.getClass() == MessageObservable.class) {
            txtAreaMessages.append(arg.toString());
            JScrollBar s = scrlPaneMessages.getVerticalScrollBar();

            s.setValue(s.getMaximum());
        }
        else if (o.getClass() == OnlineUsersObservable.class) {
            lstOnlineUsers.setListData(
                    ((OnlineUsersObservable) o).getOnlineUsers());
            lstOnlineUsers.repaint();
        }
        else if (o.getClass() == StateObservable.class) {
            if (((StateObservable) o).getState()) {
                txtServer.setEnabled(false);
                txtUser.setEnabled(false);
                txtPort.setEnabled(false);
                btnConnect.setEnabled(false);
                btnDisconnect.setEnabled(true);
                btnSend.setEnabled(true);
                txtAreaChat.setEnabled(true);
            }
            else {
                txtServer.setEnabled(true);
                txtUser.setEnabled(true);
                txtPort.setEnabled(true);
                btnConnect.setEnabled(true);
                btnDisconnect.setEnabled(false);
                btnSend.setEnabled(false);
                txtAreaChat.setEnabled(false);
                txtAreaChat.setText("");
            }
        }
        else if (o.getClass() == ReceivingFileObservable.class) {
            //starting filereceiver
            if (arg
                != null) {
                if (JOptionPane.showConfirmDialog(this, arg + " Do you want to accept?", "Receiving file", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE)
                    == JOptionPane.YES_OPTION) {

                    JFileChooser chooser = new JFileChooser("%USERPROFILE%");
                    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
                    if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
                        client.connectFileReceiver(chooser.getSelectedFile());
                    }
                }
            }
        }
        else if (o.getClass() == SendingFileObservable.class) {
            if (arg
                != null) {
                JFileChooser chooser = new JFileChooser("%USERPROFILE%");
                chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
                if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
                    client.startSendingFile(chooser.getSelectedFile());
                }

            }
        }
    }
}
